home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
commands
/
chmod.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-23
|
6KB
|
276 lines
/* chmod - change mode Author: James da Silva */
/* Author James da Silva (ihnp4!killer!jaime)
*
* a (hopefully) 7th Edition Unix compatible chmod for Minix.
*/
#include <sys/types.h>
#include <sys/stat.h>
#define isop(c) ((c=='+')||(c=='-')||(c=='='))
#define isperm(c) ((c=='r')||(c=='w')||(c=='x')||(c=='s')||(c=='t')||\
(c=='u')||(c=='g')||(c=='o'))
/* The bits associated with user, group, other */
#define U_MSK (0700 | S_ISUID)
#define G_MSK (0070 | S_ISGID)
#define O_MSK 0007
typedef unsigned short bitset; /* type used for modes */
struct stat st; /* structure returned by stat() */
char *pname, *arg;
bitset newmode, absolute(), symbolic();
int isabsolute;
main(argc, argv)
int argc;
char **argv;
{
int i;
pname = *(argv++);
if (argc < 3) usage();
arg = *argv; /* save pointer to mode arg */
/* Check for octal mode */
if (isabsolute = ((*arg >= '0') && (*arg <= '7'))) newmode = absolute();
/* Apply the mode to all files listed */
for (i = 2; i < argc; i++) {
argv++;
if (stat(*argv, &st)) { /* get current file mode */
printf("%s: cannot find `%s'\n", pname, *argv);
exit(1);
}
/* Calculate new mode for this file */
if (!isabsolute) newmode = symbolic(st.st_mode);
if (chmod(*argv, newmode)) { /* change the mode */
printf("%s: cannot chmod `%s'\n", pname, *argv);
exit(1);
}
}
exit(0);
}
/* Absolute interprets an octal mode.
* The file modes will be set to this value.
*/
bitset absolute()
{
bitset m;
char *s;
m = 0;
s = arg;
/* Convert octal string to integer */
while ((*s >= '0') && (*s <= '7')) m = m * 8 + (*(s++) - '0');
/* If something else is there, choke */
if (*s) badmode(s);
return m;
}
/* Symbolic
*
* Processes symbolic mode of the form (in EBNF):
* <symbolic> ::= <pgroup> { ',' <pgroup> }.
* <pgroup> ::= [ <who> ] <op> <permissions> { <op> <permissions> }.
*
* <who> ::= <whoch> { <whoch> }.
* <whoch> ::= 'a' | 'u' | 'g' | 'o'.
*
* <op> ::= '+' | '-' | '='.
*
* <permissions> ::= <permch> { <permch> }.
* <permch> ::= 'r' | 'w' | 'x' | 's' | 't' | 'u' | 'g' | 'o'.
*
* If <who> is omitted, 'a' is assumed, BUT umask()ed bits are uneffected.
* If <op> is '=', all unspecified permissions are turned off for this <who>.
* For permissions 'u', 'g', and 'o', the permissions are taken from the
* specified set. i.e. o=g sets the permissions for other the same as for
* group.
*
* Pain in the duff, isn't it?
*/
bitset symbolic(mode)
bitset mode;
{
int g, o, u, haswho, haspcopy;
bitset u_mask, emask, partial, other, applyop();
char *s, c, op;
s = arg;
u_mask = umask(0); /* get the umasked bits */
do { /* pgroup */
haswho = u = g = o = 0;
while (!isop(*s)) {
/* We must have a 'who' then */
haswho = 1;
switch (*s) {
case 'a': u = g = o = 1; break;
case 'u': u = 1; break;
case 'g': g = 1; break;
case 'o': o = 1; break;
default: badmode(s);
}
s++;
}
if (!haswho) {
u = g = o = 1; /* assume all */
emask = ~u_mask;/* effective umask */
} else
emask = ~0;
/* Process each given operator */
while (isop(*s)) {
op = *(s++);
other = partial = haspcopy = 0;
/* Collect the specified permissions */
while (isperm(*s)) {
/* Berkeley only allows one of 'u' 'g' or 'o'
* as permissions */
if ((*s == 'u') || (*s == 'g') || (*s == 'o'))
if (haspcopy)
badmode(s);
else
haspcopy = 1;
switch (*s) {
case 'r':
partial |= 4;
break;
case 'w':
partial |= 2;
break;
case 'x':
partial |= 1;
break;
case 'u':
partial |= (mode & U_MSK & ~S_ISUID) >> 6;
other |= mode & S_ISUID;
break;
case 'g':
partial |= (mode & G_MSK & ~S_ISGID) >> 3;
other |= mode & S_ISGID;
break;
case 'o':
partial |= (mode & O_MSK);
break;
#ifdef S_ISVTX
case 't':
other |= S_ISVTX;
break;
#endif
case 's':
if (u) other |= S_ISUID;
if (g) other |= S_ISGID;
break;
default: badmode(s);
}
s++;
}
/* Apply the op using the affected bits and masks */
if (u)
mode = applyop(mode, op, (other | (partial << 6)), emask, U_MSK);
if (g)
mode = applyop(mode, op, (other | (partial << 3)), emask, G_MSK);
if (o)
mode = applyop(mode, op, (other | partial), emask, O_MSK);
}
} while (*(s++) == ',');
/* Not at end - choke */
if (*(--s)) badmode(s);
return mode;
}
/* Applyop
*
* applies the operator to the current mode using the specified bitset
* and mask. 'bits' will contain 1's in every bit affected by the
* operator '+', '-', or '='. In the case of '=', msk is used to
* determine which bits will be forced off. 'emask' is the effective
* umask.
*/
bitset applyop(mode, op, bits, emask, msk)
char op;
bitset mode, bits, emask, msk;
{
switch (op) {
case '+':
mode |= bits & emask; /* turn these bits on */
break;
case '-':
mode &= ~(bits & emask);/* turn these off */
break;
case '=':
mode |= bits & emask; /* turn these bits on */
mode &= ~(~bits & msk & emask); /* others off */
break;
default: /* should never get here (famous last words) */
printf("%s: panic: bad op `%c' passed\n", pname, op);
}
return mode;
}
/* Usage
*
* Prints a terse usage message and exits.
*/
usage()
{
printf("Usage: %s [absolute-mode | symbolic-mode] files\n", pname);
exit(1);
}
/* Badmode
*
* Called when the parser chokes on the given mode.
* Prints a message showing the offending character and exits.
*/
badmode(s)
char *s;
{
int i, sp;
char buffer[80], *bp;
sp = s - arg + strlen(pname) + 21;
sp = sp > 79 ? 79 : sp; /* check for buffer overflow */
for (i = 0, bp = buffer; i < sp; i++, bp++) *bp = ' ';
*bp = '\0';
printf("%s: badly formed mode `%s'\n", pname, arg);
printf("%s^\n", buffer);
exit(1);
}